package com.opages.mvc.adapter.common.utils;

import javax.management.*;
import java.lang.management.ManagementFactory;
import java.net.*;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Set;

/**
 * 获取服务器ip和应用服务器端口信息
 */
public class ServerUtils {

    /** 协议 */
    private static final String PROTOCOL = "protocol";

    /** 协议 HTTP/1.1*/
    private static final String HTTP11 = "HTTP/1.1";

    /** 协议 Http11*/
    private static final String HTTP11_OTHER = "Http11";

    /** 应用服务容器*/
    private static final String CONNECTOR = "*:type=Connector,*";

    /** scheme*/
    private static final String SCHEME = "scheme";

    /** 端口*/
    private static final String PORT = "port";

    /**
     * 获取ipv4和应用程序端口信息
     * @return
     * @throws MalformedObjectNameException
     * @throws NullPointerException
     * @throws UnknownHostException
     * @throws AttributeNotFoundException
     * @throws InstanceNotFoundException
     * @throws MBeanException
     * @throws ReflectionException
     */
    public static String getIPV4EndPoints() {
        try {
            // 获取所有网络接口
            Enumeration<NetworkInterface> allNetworkInterfaces = NetworkInterface.getNetworkInterfaces();
            // 遍历所有网络接口
            for (; allNetworkInterfaces.hasMoreElements(); ) {
                NetworkInterface networkInterface = allNetworkInterfaces.nextElement();
                // 如果此网络接口为 回环接口 或者 虚拟接口(子接口) 或者 未启用 或者 描述中包含VM
                if (networkInterface.isLoopback() || networkInterface.isVirtual() || !networkInterface.isUp()
                        || networkInterface.getDisplayName().contains("VM")) {
                    // 继续下次循环
                    continue;
                }
                // 遍历此接口下的所有IP（因为包括子网掩码各种信息）
                for (Enumeration<InetAddress> inetAddressEnumeration = networkInterface
                        .getInetAddresses(); inetAddressEnumeration.hasMoreElements(); ) {
                    InetAddress inetAddress = inetAddressEnumeration.nextElement();
                    // 如果此IP不为空
                    if (inetAddress != null) {
                        // 如果此IP为IPV4 则返回
                        if (inetAddress instanceof Inet4Address) {
                            return inetAddress.getHostAddress();
                        }
                    }
                }

            }
            return "";

        } catch (SocketException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取ipv6和应用程序端口信息
     * @return
     * @throws MalformedObjectNameException
     * @throws NullPointerException
     * @throws UnknownHostException
     * @throws AttributeNotFoundException
     * @throws InstanceNotFoundException
     * @throws MBeanException
     * @throws ReflectionException
     */
    public static String getIPV6EndPoints() throws MalformedObjectNameException,
                NullPointerException, UnknownHostException,
                AttributeNotFoundException, InstanceNotFoundException,
                MBeanException, ReflectionException {
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        QueryExp subQueryHttp = Query.match(Query.attr(PROTOCOL), Query.value(HTTP11));
        QueryExp subQueryHttpOther = Query.anySubString(Query.attr(PROTOCOL), Query.value(HTTP11_OTHER));
        QueryExp query = Query.or(subQueryHttp, subQueryHttpOther);
        Set<ObjectName> connectors = mbs.queryNames(new ObjectName(CONNECTOR), query);
        String hostname = Inet6Address.getLocalHost().getHostName();
        InetAddress[] addresses = Inet6Address.getAllByName(hostname);
        return getIPArray(connectors, addresses, mbs, 6);
    }

    /**
     * 获取web container 运行端口
     * @return
     * @throws MalformedObjectNameException
     * @throws NullPointerException
     */
    public static String getPort() throws MalformedObjectNameException,
            NullPointerException{
        int port = 0;
        MBeanServer mBeanServer = null;
        ArrayList<MBeanServer> mBeanServers = MBeanServerFactory.findMBeanServer(null);
        if (mBeanServers.size() > 0) {
            mBeanServer = mBeanServers.get(0);
        }
        if (mBeanServer == null) {
            throw new IllegalStateException("没有发现JVM中关联的MBeanServer.");
        }
        Set<ObjectName> objectNames = null;
        try {
            objectNames = mBeanServer.queryNames(new ObjectName("Catalina:type=Connector,*"), null);
        } catch (MalformedObjectNameException e) {
            e.printStackTrace();
        } catch (NullPointerException e) {
            e.printStackTrace();
        }
        if (objectNames == null || objectNames.size() <= 0) {
            try {
                objectNames = mBeanServer.queryNames(new ObjectName("*:type=Connector,*"),Query.match(Query.attr("protocol"), Query.value("HTTP/1.1")));
            } catch (MalformedObjectNameException e) {
                e.printStackTrace();
            }
        }
        if (objectNames == null || objectNames.size() <= 0) {
            throw new IllegalStateException("没有发现JVM中关联的MBeanServer : " + mBeanServer.getDefaultDomain() + " 中的对象名称.");
        }
        try {
            for (ObjectName objectName : objectNames) {
                String protocol = (String) mBeanServer.getAttribute(objectName, "protocol");
                if (protocol.equals("HTTP/1.1")) {
                    port = (Integer) mBeanServer.getAttribute(objectName, "port");
                }
            }
        } catch (AttributeNotFoundException e) {
            e.printStackTrace();
        } catch (InstanceNotFoundException e) {
            e.printStackTrace();
        } catch (MBeanException e) {
            e.printStackTrace();
        } catch (ReflectionException e) {
            e.printStackTrace();
        }
        return port==0?"":port+"";
    }

    /**
     * 组合当前所有ip和端口信息
     * @param connectors
     * @param addresses
     * @param mbs
     * @param ipType 4:ipv4,6:ipv6
     * @return
     * @throws NullPointerException
     * @throws AttributeNotFoundException
     * @throws InstanceNotFoundException
     * @throws MBeanException
     * @throws ReflectionException
     */
    private static String getIPArray(Set<ObjectName> connectors,
                                    InetAddress[] addresses,
                                    MBeanServer mbs,
                                    int ipType)
            throws NullPointerException, AttributeNotFoundException,
            InstanceNotFoundException, MBeanException, ReflectionException {
        for (Iterator<ObjectName> i = connectors.iterator(); i.hasNext();) {
            ObjectName obj = i.next();
            String scheme = mbs.getAttribute(obj, SCHEME).toString();
            for (InetAddress addr : addresses) {
                if (addr.isAnyLocalAddress() || addr.isLoopbackAddress() ||
                        addr.isMulticastAddress() ) {
                    continue;
                }
                if((ipType == 4 || ipType == 6) && addr.getAddress().length == ipType){
                    String host = addr.getHostAddress();
                    String ep = scheme + "://" + host;
                    return ep;
                }
            }
        }
        return "";
    }
}
